home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
CICA 1993 April
/
CICA MS Windows - April 1993.iso
/
unzipped
/
programr
/
textview
/
demo
/
trace.c
< prev
next >
Wrap
C/C++ Source or Header
|
1991-06-13
|
17KB
|
573 lines
/*****************************************************************************
trace.c
-------
This module is an example of how you could use the TextView DLL to add
a trace system to your application. The code here manages the 'Trace'
menu set up in the application's main window, and also contains a
routine that can be called to write a message to the trace window with
an arbitrary number of arguments.
Copyright (c) Alan Phillips 1991
This source may be freely used and adapted for use in non-commercial
applications. Those wishing to include it, and the TextView DLL in
commercial or ShareWare packages should first obtain the written agreement
of the author.
The source has been edited using a tab width of 4 characters.
*****************************************************************************/
#include "stdhead.h"
#include "menu.h"
#include <stdarg.h>
/*****************************************************************************
Local Procedures
----------------
*****************************************************************************/
static void handle_file_menu(HWND,WORD);
static void window_closed(HWND);
/*****************************************************************************
Local Data
----------
*****************************************************************************/
static FARPROC lpMenuHandler; /* instance of menu handler function */
static HFONT hFont; /* handle to font used */
/*****************************************************************************
start_tracing
-------------
This routine is called when the user clicks 'start tracing' in the
main window's 'Trace' menu. If a trace window does not already exist
it creates one, updating the menu accordingly. Otherwise, it simply
sets the application's 'tracing' flag to TRUE so that the trace() routine
will actually record messages
start_tracing(hWnd)
HWND hWnd; Handle to main window
*****************************************************************************/
void start_tracing(HWND hWnd)
{
HMENU hMenu; /* handle to main menu window */
/* If we have a trace window already, just set the 'tracing' flag to
* be TRUE and adjust the menu a bit
*/
if ( hTraceWnd != NULL )
{
tracing = TRUE;
EnableMenuItem(GetMenu(hWnd),IDM_TRACE_OFF,MF_ENABLED|MF_BYCOMMAND);
EnableMenuItem(GetMenu(hWnd),IDM_TRACE_ON,MF_GRAYED|MF_BYCOMMAND);
return;
}
/* We don't have a trace window, so we'll create one. If you want to use
* your own font in the window, you need to define OWN_FONT above, and
* alter the arguments to the CreateFont function here as required
*/
#ifdef OWN_FONT
hFont = CreateFont( 18,
0,
0,
0,
700,
FALSE,
FALSE,
FALSE,
ANSI_CHARSET,
OUT_DEFAULT_PRECIS,
CLIP_DEFAULT_PRECIS,
DEFAULT_QUALITY,
DEFAULT_PITCH | FF_DONTCARE,
"Helv");
if ( hFont == NULL )
message("Cannot create font",NULL,MB_ICONSTOP);
#endif
/* Set up a procedure instance to our routine that handles clicks in the
* trace window's menu. The DLL will call back into that routine to
* notify us when the user does things. Note that you must specify this
* routine as a procedure instance, and it must be exported in the
* application's .DEF file
*/
lpMenuHandler = MakeProcInstance(menu_handler,hInst);
/* And create the TextView window we'll use for tracing */
hTraceWnd = TVCreateWindow("TRACE_WINDOW",
"Trace Window",
CW_USEDEFAULT,
CW_USEDEFAULT,
300,
200,
hInst,
#ifdef OWN_FONT
hFont,
#else
NULL,
#endif
TVS_TIMESTAMP | TVS_VSCROLL | TVS_HSCROLL |
TVS_SYSMENU | TVS_MINIMIZE |
TVS_FILESAVE | TVS_FILESAVEAS |
TVS_FILEPRINT | TVS_SCROLLMENU,
0,
4,
TRW_SIZE,
lpMenuHandler);
/* You should always check that the window has in fact been created. If
* you specified inconsistent arguments to the TVCreateWindow call the
* DLL would return a NULL handle
*/
if ( hTraceWnd == NULL )
{
message("Cannot create trace window",NULL,MB_ICONSTOP);
return;
}
/* The window now exists. We can now adjust the main window's 'Trace'
* menu to make the appropriate items enabled
*/
hMenu = GetMenu(hWnd);
EnableMenuItem(hMenu,IDM_TRACE_KILLWND,MF_ENABLED | MF_BYCOMMAND);
EnableMenuItem(hMenu,IDM_TRACE_OFF,MF_ENABLED | MF_BYCOMMAND);
EnableMenuItem(hMenu,IDM_TRACE_ON,MF_GRAYED | MF_BYCOMMAND);
EnableMenuItem(hMenu,IDM_TRACE_RESET,MF_ENABLED | MF_BYCOMMAND);
EnableMenuItem(hMenu,IDM_TRACE_SHOW,MF_ENABLED | MF_BYCOMMAND);
EnableMenuItem(hMenu,IDM_TRACE_SCR_AUTO,MF_ENABLED | MF_BYCOMMAND);
EnableMenuItem(hMenu,IDM_TRACE_SCR_MAN,MF_ENABLED | MF_BYCOMMAND);
CheckMenuItem(hMenu,IDM_TRACE_SCR_AUTO,MF_CHECKED|MF_BYCOMMAND);
EnableMenuItem(hMenu,IDM_TRACE_COPY,MF_ENABLED | MF_BYCOMMAND);
/* And now, with everything set up, we can set our own global flag to
* mark that tracing is active. Once this is done, calls to the trace()
* routine lower down will actually write to the TextView window
*/
tracing = TRUE;
}
/*****************************************************************************
kill_trace_window
-----------------
This routine is entered when the user clicks the 'kill window' item in the
main window's 'Trace' menu. It destroys the TextView window, and resets
the 'Trace' menu so that inappropriate items are no longer enabled.
stop_tracing(hWnd)
HWND hWnd; Main window handle
*****************************************************************************/
void kill_trace_window(HWND hWnd)
{
/* Call the TextView DLL to destroy the window. It's recommended that you
* don't simply send a WM_DESTROY message to the handle, as in this case
* the DLL will act as if the action was initiated from the system menu
* close option, and will call back into the application to tell it
*/
TVDestroyWindow(hTraceWnd);
/* Then call our tidy up routine to mark that tracing has stopped and
* bring the 'Trace' menu into line
*/
window_closed(hWnd);
}
/*****************************************************************************
reset_tracing
-------------
This routine is called when the user clicks the 'reset' item in the
main window's 'Trace' menu. It calls the TextView DLL to discard all
the lines stored so far in the trace window.
reset_tracing(hWnd)
HWND hWnd; Handle to main window
*****************************************************************************/
void reset_tracing(HWND hWnd)
{
/* Simply call the 'reset window' routine in the TextView DLL to reset
* the trace window
*/
TVResetWindow(hTraceWnd);
}
/*****************************************************************************
report_trace_status
-------------------
This routine is entered when the user clicks the 'report status' item in
the main window's 'Trace' menu. If the global variable hTraceWnd is NULL
there is no trace window; if not, it calls the TextView DLL to obtain
details of what the trace window is currently doing.
report_trace_status()
*****************************************************************************/
void report_trace_status()
{
TVWSTATUS stats; /* status block for window */
if ( hTraceWnd == NULL )
{
/* The global window handle is NULL, so the trace window does not
* exist
*/
message("No trace window open","Info",NULL);
return;
}
else
{
/* There is a trace window, so we ask the DLL for details about it */
if ( TVGetWindowStatus(hTraceWnd,&stats) == NULL )
message("Cannot get trace window status",NULL,MB_ICONSTOP);
else
message("Tracing is %sactive\nLines stored\t%d/%d\nScroll state\t%s\nRedrawing\t%s",
"Info",
NULL,
(tracing) ? (LPSTR)"" : (LPSTR)"in",
stats.nLinesStored,
stats.nMaxLines,
(stats.nScrollState == TV_SCR_AUTO) ? (LPSTR)"auto"
: (LPSTR)"manual",
(stats.nRedraw) ? (LPSTR)"enabled"
: (LPSTR)"disabled");
}
}
/*****************************************************************************
menu_handler
-------------
This routine is called by the TextView DLL whenever the user clicks on
a menu item in the window (including the 'close' option in the system
menu).
You use a routine such as this to keep the application informed of what
the user is doing in the TextView window. It's mandatory to have the routine
if the TextView window has been created with a 'File' menu or can be
closed from its 'System' menu; otherwise you need only have it if you want
to keep keep track, for example, of the window's scroll state.
This routine must be in the EXPORT list in the application's .DEF file
and must be declared FAR PASCAL.
menu_handler(hWnd,nMenuItem)
HWND hWnd; Window handle
WORD nMenuItem; Code for the menu item clicked
*****************************************************************************/
void FAR PASCAL menu_handler(HWND hWnd,WORD nMenuItem)
{
HMENU hMenu; /* handle to main window menu */
/* The DLL passes back a code indicating the menu item that the user has
* clicked on. Here we handle all the possible items for release 1.00.xxx
* of the TextView DLL
*/
switch (nMenuItem)
{
case TVMI_CLOSE: /* System menu close */
/* Call our handler function to clear out the window handle
* and do any other tidying up
*/
window_closed(hWnd);
break;
case TVMI_FILESAVE: /* File save */
case TVMI_FILESAVEAS: /* File save as */
case TVMI_FILEPRINT: /* File print */
/* Pass this to a function that handles each of the menu
* items
*/
handle_file_menu(hWnd,nMenuItem);
break;
case TVMI_AUTOSCROLL: /* Scroll auto */
/* Adjust the scroll items in our own menu so that they are
* step with the trace window's state
*/
hMenu = GetMenu(hMainWnd);
CheckMenuItem(hMenu,IDM_TRACE_SCR_AUTO,MF_CHECKED|MF_BYCOMMAND);
CheckMenuItem(hMenu,IDM_TRACE_SCR_MAN,MF_UNCHECKED|MF_BYCOMMAND);
break;
case TVMI_MANUALSCROLL: /* Scroll manual */
/* Adjust the scroll items in our own menu so that they are
* step with the trace window's state
*/
hMenu = GetMenu(hMainWnd);
CheckMenuItem(hMenu,IDM_TRACE_SCR_MAN,MF_CHECKED|MF_BYCOMMAND);
CheckMenuItem(hMenu,IDM_TRACE_SCR_AUTO,MF_UNCHECKED|MF_BYCOMMAND);
break;
default: /* unknown item */
/* Anything else we don't handle. Later releases of the
* TextView DLL may add further menu items to those processed
* above, so this is not necessarily an error.
*/
message("Unknown menu item (%d) clicked",NULL,
MB_ICONSTOP,nMenuItem);
break;
}
}
/*****************************************************************************
trace
-----
This routine can be called in your application to write one line to
the trace window. You pass it a FAR pointer to a null-terminated string,
and a value giving the color to use when writing the text. Optionally,
you can include arguments to be substituted in the text string with a
wsprintf call.
Note that you must cast string pointers to LPSTR explicitly if you pass
them in the optional arguments.
If the trace window does not exist, or if the global variable 'tracing'
is FALSE, the routine does nothing.
Of course, there are an infinite number of other ways of writing a trace
routine; this merely demonstrates one possible approach.
The technique used here to handle a variable number of arguments will
not work from within a DLL.
reply = trace(format,color,...)
BOOL reply; TRUE if message was written, else FALSE.
FALSE is returned only if the actual call
to TVOutputText fails
LPSTR *format; Message format string
COLORREF color; Color to use
... Optional arguments
*****************************************************************************/
BOOL trace(LPSTR format,COLORREF color,...)
{
char buffer[256]; /* text assembly buffer */
va_list arg_ptr; /* argument list pointer */
/* So that you can control tracing within the program either by destroying
* the trace window and setting the handle to NULL, or by setting a
* global flag to FALSE to inhibit it, we do something here only if we
* are actually supposed to.
*
* (Note that there is another way to control whether something appears
* in the trace window. You can call the DLL's TVSuspendWindow function
* to mark the window as suspended, and in this state any attempt to
* write a line to the window will also be ignored. However, that approach
* will always call into the DLL, so that this technique is more efficient)
*/
if ( !tracing || hTraceWnd == NULL )
return(TRUE);
/* Build the text to include any optional arguments. Note that any string
* pointers in the list must have been cast to FAR pointers
*/
va_start(arg_ptr,color);
wvsprintf(buffer,format,arg_ptr);
/* Call the DLL to write the line to the TextView window. Note that if
* the window has been marked as suspended, or if it's in manual scroll
* state, the line will be discarded.
*/
TVSetTextColor(hTraceWnd,color);
return( TVOutputText(hTraceWnd,buffer,lstrlen(buffer)) );
}
/*****************************************************************************
handle_file_menu
-----------------
This routine is called from the menu handler function to process
actions in the file menu. This has been put into a separate function to
keep the menu handler getting too large.
handle_file_menu(hWnd,type)
HWND hWnd; Handle of the TextView window concerned
WORD nMenuItem; Identity of the menu item clicked
*****************************************************************************/
static void handle_file_menu(HWND hWnd,WORD nMenuItem)
{
char *ptr; /* ptr to message text */
/* In this procedure you can take whatever you like. You might choose to
* run a dialog to ask the user for a file name; then, using the
* TVReturnData function, you could read back all the lines stored for
* the window and write them to the file. For saving to file, you could
* call the TVSaveWindowToFile function after asking the user for a
* file name.
*
* Here we simply put up a message box to report what the user clicked
* on, and nothing else. Set up a string to identify the action to start
* with...
*/
switch ( nMenuItem )
{
case TVMI_FILESAVE: /* 'File save' clicked */
ptr = "File Save";
break;
case TVMI_FILESAVEAS: /* 'File save as' clicked */
ptr = "File Save As";
break;
case TVMI_FILEPRINT: /* 'File Print' clicked */
ptr = "File Print";
break;
default: /* this shouldn't happen... */
ptr = "Unknown";
break;
}
/* Now report in a message box */
message("User clicked '%s' menu item","Info",NULL,(LPSTR)ptr);
}
/*****************************************************************************
window_closed
-------------
This routine is called from the menu handler function to take the necessary
steps when the window has been closed. It is also called from the
application when it decides to close the trace window itself.
window_closed(hWnd)
HWND hWnd; Window handler
*****************************************************************************/
static void window_closed(HWND hWnd)
{
HMENU hMenu; /* handle to main window menu */
/* Set the trace state to be off */
tracing = FALSE;
/* And set our copy of the trace window handle to NULL */
hTraceWnd = NULL;
/* Then adjust our trace menu so that the items reflect the fact that there
* is now no trace window
*/
hMenu = GetMenu(hMainWnd);
EnableMenuItem(hMenu,IDM_TRACE_ON,MF_ENABLED | MF_BYCOMMAND);
EnableMenuItem(hMenu,IDM_TRACE_KILLWND,MF_GRAYED | MF_BYCOMMAND);
EnableMenuItem(hMenu,IDM_TRACE_RESET,MF_GRAYED | MF_BYCOMMAND);
EnableMenuItem(hMenu,IDM_TRACE_SHOW,MF_GRAYED | MF_BYCOMMAND);
EnableMenuItem(hMenu,IDM_TRACE_SCR_AUTO,MF_GRAYED | MF_BYCOMMAND);
EnableMenuItem(hMenu,IDM_TRACE_SCR_MAN,MF_GRAYED | MF_BYCOMMAND);
CheckMenuItem(hMenu,IDM_TRACE_SCR_AUTO,MF_UNCHECKED|MF_BYCOMMAND);
CheckMenuItem(hMenu,IDM_TRACE_SCR_MAN,MF_UNCHECKED|MF_BYCOMMAND);
EnableMenuItem(hMenu,IDM_TRACE_COPY,MF_GRAYED | MF_BYCOMMAND);
/* Free the proc instance to the menu handler function, if there is one */
if ( lpMenuHandler != NULL )
FreeProcInstance(lpMenuHandler);
/* And delete the font we were using if we didn't let TextView use the
* default non-proportional system font
*/
#ifdef OWN_FONT
DeleteObject(hFont);
#endif
}